package bairui.international.console.web.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.method.HandlerMethod;

import com.lianjing.sh.project.authority.model.domain.jpa.TB_Authority;
import com.lianjing.sh.project.authority.model.domain.jpa.TB_RoleBase;
import com.lianjing.sh.project.authority.model.type.Type_Operator;
import com.lianjing.sh.project.authority.service.Service_Authority;
import com.lianjing.sh.project.authority.web.controller.login.C_Admin_Login_Access;
import com.lianjing.sh.spring.web.controller.enhance.exception.AuthorityExceptionConfig;
import com.lianjing.sh.spring.web.controller.enhance.exception.LoginExceptionConfig;
import com.lianjing.sh.web.security.authority.login.LoginUserInfo;

import bairui.international.model.domain.jpa.TB_Admin;
import bairui.international.model.status.State_Employee;
import bairui.international.service.Service_Admin;
import bairui.international.service.Service_Department;
import bairui.international.service.Service_Group;
import bairui.international.service.Service_Position;
import bairui.international.service.Service_Role;

@Configuration
public class Config_Security {

	@Bean
	AuthorityExceptionConfig authorityExceptionConfig(){ 
		return new AuthorityExceptionConfig(){
			@Override public String assignAccessDeniedToUrl(HandlerMethod handlerMethod) {
//				if(Util_Login.isLogin()){
//					TB_Admin bean = (TB_Admin)Util_Login.getInfo().getUser();
//					if(!bean.getChangeDefaultPasswordFlag() && handlerMethod.getBeanType()!=C_Individual_Password_ForceChangeMessage.class){
//						return "redirect:" + C_Individual_Password_ForceChangeMessage.ForceChangeMessage.Operate().getUrl();
//					}
//				}
				return "redirect:" + C_Admin_Login_Access.Access.Operate().getUrl();
			}
		};
	}
	
	@Bean
	LoginExceptionConfig myExceptionConfig(){
		return new LoginExceptionConfig(){
			@Override public String assignLoginFailToUrl(HandlerMethod handlerMethod) {
				return "redirect:"+C_Admin_Login_Access.Access.Operate().getUrl();
			}
		};
	}
	
	@Configuration
	static class InitSecurity extends WebSecurityConfigurerAdapter {
		@SuppressWarnings("unchecked")
		protected void configure(HttpSecurity http) throws Exception {
			/*
			 * headers配置
			 */
			http
				.csrf().disable()
				.headers().frameOptions().sameOrigin();
			/*
			 * logout配置
			 */
			http
				.getConfigurer(LogoutConfigurer.class)
				.addLogoutHandler(new SecurityContextLogoutHandler());
		}
	}

	/**
	 * userDetailsService
	 */
	@Bean
	@Primary
	UserDetailsService userDetailsService() { 
		return new UserDetailsService(){
			
			@Autowired private Service_Admin service_Admin;
			@Autowired private Service_Department service_Department;
			@Autowired private Service_Position service_Position;
			@Autowired private Service_Group service_Group;
			@Autowired private Service_Role service_Role;
			@Autowired private Service_Authority service_Authority;
			
			@Override
			public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
				TB_Admin bean = service_Admin.findOne(it->it.username.eq(username));
				if(null == bean){
					throw new UsernameNotFoundException("用户不存在");
				}
				if(bean.getFreezenFlag()){
					throw new UsernameNotFoundException("用户已被冻结");
				}
				if(bean.getState() == State_Employee.Dimission){
					throw new UsernameNotFoundException("用户已离职");
				}
				/*
				 * 授权
				 */
				// 一般授权
				Collection<GrantedAuthority> authorities = new LinkedList<GrantedAuthority>();
				// 冻结检查
				if(bean.getFreezenFlag()){
					return createLoginUserInfo(bean, authorities);
				}
				//
				if(bean.getOperatorType()==Type_Operator.Admin){
//					if(!bean.getChangeDefaultPasswordFlag()){
//						authorities.add(new SimpleGrantedAuthority("ROLE_CHANGEDEFAULTPASSWORD"));
//						return createLoginUserInfo(bean, authorities);
//					}else{
						authorities.add(new SimpleGrantedAuthority("ROLE_AUTHENTICATED"));
//					}
					// 来自部门
					List<TB_RoleBase> list = new ArrayList<>();
						list.addAll(service_Department.list(it->it.admins.any().eq(bean)));
						list.addAll(service_Position.list(it->it.admins.any().eq(bean)));
						list.addAll(service_Group.list(it->it.admins.any().eq(bean)));
						list.addAll(service_Role.list(it->it.admins.any().eq(bean)));
					//
					for(TB_Authority it : service_Authority.list(it->it.roleBases.any().in(list))){
						authorities.add(new SimpleGrantedAuthority(it.getName().toUpperCase()));
					}
				}else if(bean.getOperatorType()==Type_Operator.RootAdmin){
					authorities.add(new SimpleGrantedAuthority("ROLE_AUTHENTICATED"));
					authorities.add(new SimpleGrantedAuthority("ROLE_ROOT"));
				}
				/*	
				 * 
				 */
				return createLoginUserInfo(bean, authorities);
			}
		};
	}
	
	private LoginUserInfo createLoginUserInfo(TB_Admin bean, Collection<GrantedAuthority> authorities){
		return new LoginUserInfo(
				bean, 
				bean.getUsername(),
				bean.getPassword(),
				true, true, true, true, 
				authorities
			);
	}
	
	/**
	 *  AuthenticationProvider
	 */
	@Bean
	AuthenticationProvider daoAuthenticationProvider(){
		DaoAuthenticationProvider bean = new DaoAuthenticationProvider();
			bean.setUserDetailsService(userDetailsService());
			bean.setHideUserNotFoundExceptions(false);
			bean.setPasswordEncoder(passwordEncoder());
//			bean.setSaltSource(reflectionSaltSource());
		return bean;
	}
	
	/**
	 * 密码加密方式
	 */
	@Bean
	BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
//	/**
//	 * SaltSource
//	 * Crypt 加密方式不需要
//	 */
//	@Bean
//	SaltSource reflectionSaltSource(){
//		ReflectionSaltSource bean = new ReflectionSaltSource();
//		bean.setUserPropertyToUse("username");;
//		return bean;
//	}

}